﻿package com.spikything.audio {
	
	import com.spikything.audio.AudioEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundMixer;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.events.Event;
	import flash.display.Sprite;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	
	public class SoundItem extends Sprite {
		
		private var MP3OFFSET 			:Number 	= 20;
		private var _mp3offset			:Number		= 60;
		private var _sound 				:Sound;
		private var _channel 			:SoundChannel;
		private var _volume 			:Number;
		private var _trans 				:SoundTransform;
		private var _loaded 			:Boolean;
		private var _isMuted 			:Boolean;
		private var _name 				:String;
		private var _looping 			:Boolean;
		private var preemptiveTimer 	:Timer;
		private var preemptiveLooping 	:Boolean 	= true;
		//private var _stopped 			:Boolean;
		
		public function SoundItem (url:String="", name:String="") {
			_sound = new Sound();
			volume = 1;
			soundName = name;
			if (url.length) loadSound(url, name);
		}
		
		//
		public function loadSound (url:String, name:String=""):void {
			soundName = name;
			_loaded = false;
			var req:URLRequest = new URLRequest(url);
			_sound.load(req);
			_sound.addEventListener(Event.COMPLETE, loadComplete);
		}
		
		//
		private function loadComplete (e:Event):void {
			_loaded = true;
			dispatchEvent(new AudioEvent(AudioEvent.LOADED, soundName));
		}
		
		//
		public function start (loop:Boolean=false, offset:Number=0, trans:SoundTransform=null):SoundChannel {
			if (!_loaded) return null;
			_looping = loop;
			//_channel = _sound.play(offset, loop==true ? 9999 : 0, trans);
			_channel = _sound.play(offset, 0, trans);
			_trans = _channel.soundTransform;
			volume = volume;
			_channel.addEventListener(Event.SOUND_COMPLETE, onSoundComplete);
			
			// use this if you want to start the new loop before the other finishes
			if (loop && preemptiveLooping) {
				preemptiveTimer = new Timer(length-_mp3offset, 1);
				preemptiveTimer.addEventListener(TimerEvent.TIMER, restartSound);
				preemptiveTimer.start();
			}
			
			return _channel;
		}
		
		private function restartSound (e:Event):void {
			_channel = start(true, MP3OFFSET, _trans);
		}
		//
		public function stop ():void {
			//_stopped = false;
			_channel.stop();
		}
		
		//
		protected function onSoundComplete (e:Event):void {
			_channel.removeEventListener(Event.SOUND_COMPLETE, onSoundComplete);
			if (_looping) {
				// use this if you are NOT using the pre-emptive timer
				if (!preemptiveLooping) restartSound(new Event(""));
			} else {
				dispatchEvent(new AudioEvent(AudioEvent.FINISHED, soundName));
			}
		}
		
		//
		public function fadeOut ():void {
			preemptiveTimer.stop();
			preemptiveTimer.removeEventListener(TimerEvent.TIMER, restartSound);
			addEventListener(Event.ENTER_FRAME, fadeOutSound);
		}
		
		//
		private function fadeOutSound (e:Event):void {
			if (_trans.volume > 0) {
				_trans.volume -= 0.1;
				_channel.soundTransform = _trans;
			} else {
				removeEventListener(Event.ENTER_FRAME, fadeOutSound);
				_channel.stop();
			}
		}
		
		//
		public function fadeIn (loop:Boolean=false, offset:Number=0, trans:SoundTransform=null):SoundChannel {
			start(loop, offset, trans);
			_trans = _channel.soundTransform;
			_trans.volume = 0;
			_channel.soundTransform = _trans;
			this.addEventListener(Event.ENTER_FRAME, fadeInSound);
			return _channel;
		}
		
		//
		private function fadeInSound (e:Event):void {
			//if (!_channel) return;
			if (_trans.volume < 1) { //_volume
				_trans.volume += 0.1;
				_channel.soundTransform = _trans;
			} else {
				_trans.volume = 1; //volume;
				_channel.soundTransform = _trans;
				removeEventListener(Event.ENTER_FRAME, fadeInSound); // if (_looping)
			}
			/*
			if (!_looping) {
				//check the position in the sound - we need to fade it out when it gets near the end
				if (_sound.length - _channel.position < 3000) {
					this.removeEventListener(Event.ENTER_FRAME, fadeInSound);
					fadeOut();
				}
			}
			*/
		}
		
		//
		public function get loaded ():Boolean { return _loaded };
		public function get length ():Number { return _sound.length };
		public function get position ():Number { return _channel ? _channel.position : 0 };
		
		//public function set looping ($looping:Boolean):void { _looping = $looping };
		//public function get looping ():Boolean { return _looping };
		
		public function set soundName (value:String):void { _name = value };
		public function get soundName ():String { return _name };
		
		public function get volume ():Number { return _volume };
		public function set volume ($volume:Number):void {
			var vol:Number = isMuted ? 0 : 1; //$volume;
			if (_channel) {
				_trans = _channel.soundTransform;
				_trans.volume = vol;
				_channel.soundTransform = _trans;
			}
		}
		
		//public function set stopped ($stopped:Boolean):void { _stopped = $stopped };
		//public function get stopped ():Boolean { return _stopped };
		
		public function get isMuted ():Boolean { return _isMuted };
		public function set isMuted (value:Boolean):void {
			_isMuted = value;
			volume = volume;
			//for each (var s:SoundItem in soundItems) s.isMuted = value;
		}
		
		public function set mp3offset (value:Number):void {
			_mp3offset = value;
		}
		
		public function set _MP3OFFSET(value:Number):void { MP3OFFSET == value}
		
		public override function toString ():String { return soundName };
		
	}
}